﻿using System.Linq;
using System.Threading.Tasks;
using Dpx.Models;
using Dpx.Services;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using MvvmHelpers;

namespace Dpx.ViewModels {
    /// <summary>
    /// 诗词收藏页ViewModel。
    /// </summary>
    public class FavoritePageViewModel : ViewModelBase {
        /******** 私有变量 ********/

        /// <summary>
        /// 页面已加载。
        /// </summary>
        private volatile bool pageLoaded;

        /// <summary>
        /// 页面已加载锁。
        /// </summary>
        private readonly object pageLoadedLock = new object();


        /******** 构造函数 ********/

        /// <summary>
        /// 收藏存储。
        /// </summary>
        private readonly IFavoriteStorage _favoriteStorage;

        /// <summary>
        /// 诗词存储。
        /// </summary>
        private readonly IPoetryStorage _poetryStorage;

        /// <summary>
        /// 内容导航服务。
        /// </summary>
        private readonly IContentNavigationService _contentNavigationService;

        /// <summary>
        /// 诗词收藏页ViewModel。
        /// </summary>
        /// <param name="favoriteStorage">收藏存储。</param>
        /// <param name="poetryStorage">诗词存储。</param>
        /// <param name="contentNavigationService">内容导航服务。</param>
        public FavoritePageViewModel(IFavoriteStorage favoriteStorage,
            IPoetryStorage poetryStorage,
            IContentNavigationService contentNavigationService) {
            _favoriteStorage = favoriteStorage;
            _poetryStorage = poetryStorage;
            _contentNavigationService = contentNavigationService;
            favoriteStorage.Updated += FavoriteStorageOnUpdated;
        }

        /******** 绑定属性 ********/

        /// <summary>
        /// 诗词收藏集合。
        /// </summary>
        public ObservableRangeCollection<PoetryFavorite>
            PoetryFavoriteCollection { get; } =
            new ObservableRangeCollection<PoetryFavorite>();

        /// <summary>
        /// 正在载入。
        /// </summary>
        public bool Loading {
            get => _loading;
            set => Set(nameof(Loading), ref _loading, value);
        }

        /// <summary>
        /// 正在载入。
        /// </summary>
        private bool _loading;

        /******** 绑定命令 ********/

        /// <summary>
        /// 页面显示命令。
        /// </summary>
        public RelayCommand PageAppearingCommand =>
            _pageAppearingCommand ??= new RelayCommand(
                async () => await PageAppearingCommandFunction());

        /// <summary>
        /// 页面显示命令。
        /// </summary>
        private RelayCommand _pageAppearingCommand;

        internal async Task PageAppearingCommandFunction() {
            if (pageLoaded) return;
            lock (pageLoadedLock) {
                if (pageLoaded) return;
                pageLoaded = true;
            }

            Loading = true;
            PoetryFavoriteCollection.Clear();
            var favoriteList = await _favoriteStorage.GetFavoritesAsync();

            var poetryTaskList = favoriteList.Select(p =>
                _poetryStorage.GetPoetryAsync(p.PoetryId)).ToList();

            PoetryFavoriteCollection.AddRange(await Task.WhenAll(
                favoriteList.Select(async p => new PoetryFavorite {
                    Poetry = await _poetryStorage.GetPoetryAsync(p.PoetryId),
                    Favorite = p
                })));
            Loading = false;
        }

        /// <summary>
        /// 诗词点击命令。
        /// </summary>
        public RelayCommand<PoetryFavorite> PoetryTappedCommand =>
            _poetryTappedCommand ??= new RelayCommand<PoetryFavorite>(async poetryFavorite =>
                await PoetryTappedCommandFunction(poetryFavorite));

        /// <summary>
        /// 诗词点击命令。
        /// </summary>
        private RelayCommand<PoetryFavorite> _poetryTappedCommand;

        internal async Task
            PoetryTappedCommandFunction(PoetryFavorite poetryFavorite) =>
            await _contentNavigationService.NavigateToAsync(
                ContentNavigationConstant.DetailPage, poetryFavorite.Poetry);

        /******** 私有方法 ********/

        private async void FavoriteStorageOnUpdated(object sender,
            FavoriteStorageUpdatedEventArgs e) {
            var favorite = e.UpdatedFavorite;
            PoetryFavoriteCollection.Remove(
                PoetryFavoriteCollection.FirstOrDefault(p =>
                    p.Favorite.PoetryId == favorite.PoetryId));

            if (!favorite.IsFavorite) return;
            var poetryFavorite = new PoetryFavorite {
                Poetry =
                    await _poetryStorage.GetPoetryAsync(favorite.PoetryId),
                Favorite = favorite
            };
            PoetryFavoriteCollection.Insert(0, poetryFavorite);
        }
    }
}